home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / prog_pas / ddplus63.zip / ASYNC2.PAS next >
Pascal/Delphi Source File  |  1993-10-15  |  59KB  |  1,276 lines

  1. {*--------------------------------------------------------------------------*}
  2. {*                                                                          *}
  3. {*  Status byte definition (C_Status):                                      *}
  4. {*                                                                          *}
  5. {*  7   6   5   4   3   2   1   0                                           *}
  6. {*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
  7. {*  |   |   |   |   |   |   |________ Input buffer full                     *}
  8. {*  |   |   |   |   |   |____________ Output buffer empty                   *}
  9. {*  |   |   |   |   |________________ Output buffer full                    *}
  10. {*  |   |   |   |____________________ Input buffer overflow                 *}
  11. {*  |   |   |________________________ Output buffer overflow                *}
  12. {*  |   |____________________________ Hard handshake active (xmit stopped)  *}
  13. {*  |________________________________ Soft handshake active (xmit stopped)  *}
  14. {*                                                                          *}
  15. {*  Control byte definition (C_Ctrl):                                       *}
  16. {*                                                                          *}
  17. {*  7   6   5   4   3   2   1   0                                           *}
  18. {*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
  19. {*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
  20. {*  |   |   |   |   |   |____________ Enable software handshake             *}
  21. {*  |   |   |   |   |________________                                       *}
  22. {*  |   |   |   |____________________                                       *}
  23. {*  |   |   |________________________                                       *}
  24. {*  |   |____________________________                                       *}
  25. {*  |________________________________                                       *}
  26. {*                                                                          *}
  27. {****************************************************************************}
  28.  
  29. {$R-,V-,B-,S-}
  30.  
  31. Unit ASYNC2;
  32.  
  33. INTERFACE
  34.  
  35. {----------------------------------------------------------------------------}
  36.  
  37. Const
  38.   C_MinBaud = 300;
  39.   C_MaxBaud = 115200;
  40.   C_MaxPort = 4;
  41.   C_MaxCom : byte = C_MaxPort;
  42.   D_PortAddr : Array[1..C_MaxPort] Of Word = ($03F8,$02F8,$03E8,$02E8);
  43.   D_PortInt  : Array[1..C_MaxPort] Of Byte = (4,3,4,3);
  44.  
  45. {----------------------------------------------------------------------------}
  46.  
  47. Type
  48.   C_VectorArray  = Array[0..15] Of Pointer;
  49.   C_PointerArray = Array[1..C_MaxPort]  Of Pointer;
  50.   C_WordArray    = Array[1..C_MaxPort] Of Word;
  51.   C_ByteArray    = Array[1..C_MaxPort] Of Byte;
  52.   C_CharArray    = Array[1..C_MaxPort] Of Char;
  53.   C_BooleanArray = Array[1..C_MaxPort] Of Boolean;
  54.  
  55. {----------------------------------------------------------------------------}
  56.  
  57. Var
  58.   { Base port addresses & interrupt usage }
  59.   C_PortAddr : Array[1..C_MaxPort] Of Word;
  60.   C_PortInt  : Array[1..C_MaxPort] Of Byte;
  61.   ComPort  : Byte;
  62.   C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  63.   C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  64.   C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  65.   C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  66.   C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  67.   C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  68.   C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  69.   C_XL3Ptr               : C_ByteArray;
  70.   C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  71.   C_Temp                 : Word;              { Used for debugging }
  72.   C_msrport              : word;
  73. { RTSOn,RTSOff           : Word;}             { RTS assert/drop buffer points }
  74.   oldier,oldmcr          : byte;
  75.   c_buffull              : c_wordarray;
  76.   C_Cascade              : Byte;              { Flag set 0 normally }
  77.   C_CascadeOK            : boolean;           { Flag if IRQ > 7 }
  78.  
  79. {----------------------------------------------------------------------------}
  80.  
  81. Function  ComReadCh(ComPort:Byte) : Char;
  82. Function  ComReadChW(ComPort:Byte) : Char;
  83. { Procedure ComWriteCh(ComPort:Byte; Ch:Char); }
  84. Procedure ComWriteChW(ComPort:Byte; Ch:Char);
  85. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  86. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  87. {
  88. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  89. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  90.  }
  91. Function  CTSStat(ComPort:Byte) : Boolean;
  92. Function  RTSStat(ComPort:Byte) : Boolean;
  93. Function  DSRStat(ComPort:Byte) : Boolean;
  94. Function  RIStat(ComPort:Byte) : Boolean;
  95. Function  DCDStat(ComPort:Byte) : Boolean;
  96. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  97. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  98. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  99. Procedure ClearCom(ComPort:Byte; IO:Char);
  100. Function  ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  101. Procedure ComWaitForClear(ComPort:Byte);
  102. Procedure ComWrite(ComPort:Byte; St:String);
  103. Procedure ComWriteln(ComPort:Byte; St:String);
  104. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  105. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  106. Function  ComExist(ComPort:Byte) : Boolean;
  107. Function  ComTrueBaud(Baud:Longint) : Real;
  108. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  109. Function  OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  110. Procedure CloseCom(ComPort:Byte);
  111. Procedure CloseAllComs;
  112.  
  113. {----------------------------------------------------------------------------}
  114.  
  115. IMPLEMENTATION
  116.  
  117. Uses DOS,CRT;
  118.  
  119. {$L SLASYNC.OBJ}
  120.  
  121. Const
  122.   C_IER = 1;                           { 8250 register offsets }
  123.   C_IIR = 2;
  124.   C_LCR = 3;
  125.   C_MCR = 4;
  126.   C_LSR = 5;
  127.   C_MSR = 6;
  128.   C_SCR = 7;
  129.  
  130. Var
  131.   C_OldINTVec : C_VectorArray;        { Storage for old hardware INT vectors }
  132.   X : Byte;                            { Used by initialization code }
  133.  
  134. {****************************************************************************}
  135. {*                                                                          *}
  136. {*  Procedure INT_Handler; External;                                        *}
  137. {*                                                                          *}
  138. {*  Hardware interrupts 0-15 (vectors $08 - $0F,$70 - $77) are pointed to   *}
  139. {*  this routine.  It is for internal use only and should NOT be called     *}
  140. {*  directly.  Written in assembly language (see SLASYNC.ASM).              *}
  141. {*                                                                          *}
  142. {****************************************************************************}
  143.  
  144. Procedure INT_Handler; External;
  145.  
  146. {****************************************************************************}
  147. {*                                                                          *}
  148. {*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
  149. {*                                                                          *}
  150. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  151. {*                                                                          *}
  152. {*  Returns character from input buffer of specified port.  If the buffer   *}
  153. {*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
  154. {*  Written in assembly language for best possible speed (see ASYNC11.ASM)  *}
  155. {*                                                                          *}
  156. {****************************************************************************}
  157.  
  158. Function ComReadCh(ComPort:Byte) : Char; External;
  159.  
  160. {****************************************************************************}
  161. {*                                                                          *}
  162. {*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
  163. {*                                                                          *}
  164. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  165. {*                                                                          *}
  166. {*  Works like ComReadCh, but will wait until at least 1 character is       *}
  167. {*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
  168. {*  works much like the ReadKey predefined function.  Written in assembly   *}
  169. {*  language to maximize performance (see ASYNC11.ASM)                      *}
  170. {*                                                                          *}
  171. {****************************************************************************}
  172.  
  173. Function ComReadChW(ComPort:Byte) : Char; External;
  174.  
  175. {****************************************************************************}
  176. {*                                                                          *}
  177. {*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
  178. {*                                                                          *}
  179. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  180. {*  Ch:Char       ->  Character to send                                     *}
  181. {*                                                                          *}
  182. {*  Places the character [Ch] in the transmit buffer of the specified port. *}
  183. {*  If the port specified is not open or nonexistent, or if the buffer is   *}
  184. {*  filled, the character is discarded.  Written in assembly language to    *}
  185. {*  maximize performance (see ASYNC11.ASM)                                  *}
  186. {*                                                                          *}
  187. {****************************************************************************}
  188.  
  189. Procedure ComWriteCh(ComPort:Byte; Ch:Char); External;
  190.  
  191. {****************************************************************************}
  192. {*                                                                          *}
  193. {*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
  194. {*                                                                          *}
  195. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  196. {*  Ch:Char       ->  Character to send                                     *}
  197. {*                                                                          *}
  198. {*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
  199. {*  available in the output buffer before attempting to place the character *}
  200. {*  [Ch] in it.  Allows the programmer to send characters without regard to *}
  201. {*  available buffer space.  Written in assembly language to maximize       *}
  202. {*  performance (see ASYNC11.ASM)                                           *}
  203. {*                                                                          *}
  204. {****************************************************************************}
  205.  
  206. Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;
  207.  
  208. {****************************************************************************}
  209. {*                                                                          *}
  210. {*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
  211. {*                                                                          *}
  212. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  213. {*                      Call ignored if out-of-range                        *}
  214. {*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
  215. {*                                                                          *}
  216. {*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
  217. {*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
  218. {*  state, signalling to a remote system that the host is "on-line"         *}
  219. {*  (although not nessesarily ready to receive data - see SetRTS).          *}
  220. {*                                                                          *}
  221. {****************************************************************************}
  222.  
  223. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  224.  
  225. Var
  226.   P,X : Integer;
  227.  
  228. Begin
  229.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  230.   P := C_PortAddr[ComPort];
  231.  
  232.   X := Port[P+C_MCR];
  233.   If Assert Then
  234.     X := X Or $01
  235.   Else
  236.     X := X And $FE;
  237.   Port[P+C_MCR] := X;
  238. End;
  239.  
  240. {****************************************************************************}
  241. {*                                                                          *}
  242. {*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
  243. {*                                                                          *}
  244. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  245. {*                      Call ignored if out-of-range                        *}
  246. {*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
  247. {*                                                                          *}
  248. {*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
  249. {*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
  250. {*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
  251. {*  should NOT be used if RTS handshaking is enabled.                       *}
  252. {*                                                                          *}
  253. {****************************************************************************}
  254.  
  255. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  256.  
  257. Var
  258.   P,X : Integer;
  259.  
  260. Begin
  261.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  262.   P := C_PortAddr[ComPort];
  263.  
  264.   X := Port[P+C_MCR];
  265.   If Assert Then
  266.     X := X Or $02
  267.   Else
  268.     X := X And $FD;
  269.   Port[P+C_MCR] := X;
  270. End;
  271.  
  272. {****************************************************************************}
  273. {*                                                                          *}
  274. {*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
  275. {*                                                                          *}
  276. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  277. {*                      Call ignored if out-of-range                        *}
  278. {*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
  279. {*                                                                          *}
  280. {*  SetOUT1 is provided for reasons of completeness only, since the         *}
  281. {*  standard PC/XT/AT configurations do not utilize this control signal.    *}
  282. {*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
  283. {*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
  284. {*  of the 8250 (but not on the port itself).                               *}
  285. {*                                                                          *}
  286. {****************************************************************************}
  287. {
  288. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  289.  
  290. Var
  291.   P,X : Integer;
  292.  
  293. Begin
  294.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  295.   P := C_PortAddr[ComPort];
  296.  
  297.   X := Port[P+C_MCR];
  298.   If Assert Then
  299.     X := X Or $04
  300.   Else
  301.     X := X And $FB;
  302.   Port[P+C_MCR] := X;
  303. End;
  304.  }
  305. {****************************************************************************}
  306. {*                                                                          *}
  307. {*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
  308. {*                                                                          *}
  309. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  310. {*                      Call ignored if out-of-range                        *}
  311. {*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
  312. {*                                                                          *}
  313. {*  The OUT2 signal line, although not available on the port itself, is     *}
  314. {*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
  315. {*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
  316. {*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
  317. {*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
  318. {*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
  319. {*                                                                          *}
  320. {****************************************************************************}
  321. {
  322. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  323.  
  324. Var
  325.   P,X : Integer;
  326.  
  327. Begin
  328.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  329.   P := C_PortAddr[ComPort];
  330.  
  331.   X := Port[P+C_MCR];
  332.   If Assert Then
  333.     X := X Or $08
  334.   Else
  335.     X := X And $F7;
  336.   Port[P+C_MCR] := X;
  337. End;
  338.  }
  339. {****************************************************************************}
  340. {*                                                                          *}
  341. {*  Function CTSStat(ComPort:Byte) : Boolean                                *}
  342. {*                                                                          *}
  343. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  344. {*                    Call ignored if out-of-range                          *}
  345. {*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
  346. {*                                                                          *}
  347. {*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
  348. {*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
  349. {*  signals the host (this computer) that the receiver is ready to accept   *}
  350. {*  data (in contrast to the DSR line, which signals the receiver as        *}
  351. {*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
  352. {*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
  353. {*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
  354. {*  terrogate this line manually.                                           *}
  355. {*                                                                          *}
  356. {****************************************************************************}
  357.  
  358. Function CTSStat(ComPort:Byte) : Boolean;
  359.  
  360. Begin
  361.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  362.     CTSStat := False
  363.   Else
  364.     CTSStat := (Port[C_PortAddr[ComPort]+C_MSR] And $10 <> $10);
  365. End;
  366.  
  367. {****************************************************************************}
  368. {*                                                                          *}
  369. {*  Function RTSStat(ComPort:Byte) : Boolean                                *}
  370. {*                                                                          *}
  371. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  372. {*                    Call ignored if out-of-range                          *}
  373. {*  Returns status of Ready-To-Send line (TRUE if RTS asserted)             *}
  374. {*                                                                          *}
  375. {****************************************************************************}
  376.  
  377.  
  378. Function RTSStat(ComPort:Byte) : Boolean;
  379.  
  380. Begin
  381.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  382.     RTSStat := False
  383.   Else
  384.     RTSStat := (Port[C_PortAddr[ComPort]+C_LSR] And $20 <> $20);
  385. End;
  386.  
  387. {****************************************************************************}
  388. {*                                                                          *}
  389. {*  Function DSRStat(ComPort:Byte) : Boolean                                *}
  390. {*                                                                          *}
  391. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  392. {*                    Call ignored if out-of-range                          *}
  393. {*  Returns status of Data Set Ready (DSR) signal line.                     *}
  394. {*                                                                          *}
  395. {*  The Data Set Ready (DSR) line is typically used by a remote station     *}
  396. {*  to signal the host system that it is on-line (although not nessesarily  *}
  397. {*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
  398. {*  line asserted if DSRStat returns TRUE.                                  *}
  399. {*                                                                          *}
  400. {****************************************************************************}
  401.  
  402. Function DSRStat(ComPort:Byte) : Boolean;
  403.  
  404. Begin
  405.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  406.     DSRStat := False
  407.   Else
  408.     DSRStat := (Port[C_PortAddr[ComPort]+C_MSR] And $20) > 0;
  409. End;
  410.  
  411. {****************************************************************************}
  412. {*                                                                          *}
  413. {*  Function RIStat(ComPort:Byte) : Boolean                                 *}
  414. {*                                                                          *}
  415. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  416. {*                    Call ignored if out-of-range                          *}
  417. {*                                                                          *}
  418. {*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
  419. {*  typically used only by modems, and indicates that the modem has detect- *}
  420. {*  ed an incoming call if RIStat returns TRUE.                             *}
  421. {*                                                                          *}
  422. {****************************************************************************}
  423.  
  424. Function RIStat(ComPort:Byte) : Boolean;
  425.  
  426. Begin
  427.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  428.     RIStat := False
  429.   Else
  430.     RIStat := (Port[C_PortAddr[ComPort]+C_MSR] And $40) > 0;
  431. End;
  432.  
  433. {****************************************************************************}
  434. {*                                                                          *}
  435. {*  Function DCDStat(ComPort:Byte) : Boolean                                *}
  436. {*                                                                          *}
  437. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  438. {*                    Call ignored if out-of-range                          *}
  439. {*                                                                          *}
  440. {*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
  441. {*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
  442. {*  the modem indicates that it has successfuly linked with another modem   *}
  443. {*  device at another site.                                                 *}
  444. {*                                                                          *}
  445. {****************************************************************************}
  446.  
  447. Function DCDStat(ComPort:Byte) : Boolean;
  448.  
  449. Begin
  450.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  451.     DCDStat := False
  452.   Else
  453.     DCDStat := (Port[C_PortAddr[ComPort]+C_MSR] And $80) > 0;
  454. End;
  455.  
  456. {****************************************************************************}
  457. {*                                                                          *}
  458. {*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
  459. {*                                                                          *}
  460. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  461. {*                    Request ignored if out of range or unopened.          *}
  462. {*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
  463. {*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
  464. {*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
  465. {*                                                                          *}
  466. {*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
  467. {*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
  468. {*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
  469. {*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
  470. {*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
  471. {*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
  472. {*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
  473. {*  The actual handshaking control is located in the interrupt driver for   *}
  474. {*  the port (see ASYNC11.ASM).                                             *}
  475. {*                                                                          *}
  476. {****************************************************************************}
  477.  
  478. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  479.  
  480. Var
  481.   X : Byte;
  482.  
  483. Begin
  484.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  485.  
  486.   X := C_Ctrl[ComPort];
  487.   If Mode Then X := X Or $01 Else X := X And $FE;
  488.   C_Ctrl[ComPort] := X;
  489.  
  490.   If Mode Then
  491.     Begin
  492.       If (RTSOff >= C_InSize[ComPort]) Then RTSOff := C_InSize[ComPort] - 1;
  493.       If (RTSOn > RTSOff) Then RTSOff := RTSOn;
  494.       C_RTSOn[ComPort] := RTSOn;
  495.       C_RTSOff[ComPort] := RTSOff;
  496.     End;
  497. End;
  498.  
  499. {****************************************************************************}
  500. {*                                                                          *}
  501. {*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
  502. {*                                                                          *}
  503. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  504. {*                    Request ignored if out of range or unopened.          *}
  505. {*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
  506. {*                                                                          *}
  507. {*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
  508. {*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
  509. {*  if the remote drops the CTS line, the transmitter will be disabled      *}
  510. {*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
  511. {*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
  512. {*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
  513. {*  in any combination.  The actual logic for CTS handshaking is located    *}
  514. {*  in the communications interrupt driver (see ASYNC11.ASM).               *}
  515. {*                                                                          *}
  516. {****************************************************************************}
  517.  
  518. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  519.  
  520. Var
  521.   X : Byte;
  522.  
  523. Begin
  524.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  525.  
  526.   X := C_Ctrl[ComPort];
  527.   If Mode Then X := X Or $02 Else X := X And $FD;
  528.   C_Ctrl[ComPort] := X;
  529. End;
  530.  
  531. {****************************************************************************}
  532. {*                                                                          *}
  533. {*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
  534. {*                                                                          *}
  535. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  536. {*                    Request ignored if out of range or unopened.          *}
  537. {*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
  538. {*  Start:Char    ->  START control character (usually ^Q)                  *}
  539. {*                    Defaults to ^Q if character passed is >= <Space>      *}
  540. {*  Stop:Char     ->  STOP control character (usually ^S)                   *}
  541. {*                    Defaults to ^S if character passed is >= <Space>      *}
  542. {*                                                                          *}
  543. {*  SoftHandshake controls the usage of "Software" (control-character)      *}
  544. {*  handshaking on transmission.  If "software handshake" is enabled        *}
  545. {*  ([Mode] is TRUE), transmission will be halted if the character in       *}
  546. {*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
  547. {*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
  548. {*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
  549. {*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
  550. {*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
  551. {*  for <Stop>) will be used.  Software handshaking control is implimented  *}
  552. {*  within the communications interrupt driver (see ASYNC11.ASM).           *}
  553. {*                                                                          *}
  554. {****************************************************************************}
  555.  
  556. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  557.  
  558. Var
  559.   X : Byte;
  560.  
  561. Begin
  562.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  563.  
  564.   X := C_Ctrl[ComPort];
  565.   If Mode Then
  566.     Begin
  567.       X := X Or $04;
  568.       If Start=Stop Then Begin Start := ^Q; Stop := ^S; End;
  569.       If Start>#32 Then Start := ^Q;
  570.       If Stop>#32 Then Stop := ^S;
  571.       C_StartChar[ComPort] := Start;
  572.       C_StopChar[ComPort] := Stop;
  573.     End
  574.   Else
  575.     X := X And $FB;
  576.   C_Ctrl[ComPort] := X;
  577. End;
  578.  
  579. {****************************************************************************}
  580. {*                                                                          *}
  581. {*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
  582. {*                                                                          *}
  583. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  584. {*                    Request ignored if out of range or unopened.          *}
  585. {*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
  586. {*                    No action taken if action code unrecognized.          *}
  587. {*                                                                          *}
  588. {*  ClearCom allows the user to completely clear the contents of either     *}
  589. {*  the input (receive) and/or output (transmit) buffers.  The "action      *}
  590. {*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
  591. {*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
  592. {*  if you wish to cancel a transmitted message or ignore part of a         *}
  593. {*  received message.                                                       *}
  594. {*                                                                          *}
  595. {****************************************************************************}
  596.  
  597. Procedure ClearCom(ComPort:Byte; IO:Char);
  598.  
  599. Var
  600.   P,X : Word;
  601.  
  602. Begin
  603.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  604.  
  605.   IO := Upcase(IO);
  606.   P := C_PortAddr[ComPort];
  607.  
  608.   Inline($FA);
  609.   If (IO='I') Or (IO='B') Then
  610.     Begin
  611.       C_InHead[ComPort] := 0;
  612.       C_InTail[ComPort] := 0;
  613.       C_Status[ComPort] := (C_Status[ComPort] And $EC) Or $01;
  614.       X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  615.     End;
  616.   If (IO='O') Or (IO='B') Then
  617.     Begin
  618.       C_OutHead[ComPort] := 0;
  619.       C_OutTail[ComPort] := 0;
  620.       C_Status[ComPort] := (C_Status[ComPort] And $D3) Or $04;
  621.       X := Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  622.     End;
  623.   Inline($FB);
  624. End;
  625.  
  626. {****************************************************************************}
  627. {*                                                                          *}
  628. {*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
  629. {*                                                                          *}
  630. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  631. {*                    Returns 0 if Port # invalid or unopened.              *}
  632. {*  IO:Char       ->  Action code; I=Input, O=Output                        *}
  633. {*                    Returns 0 if action code unrecognized.                *}
  634. {*                                                                          *}
  635. {*  ComBufferLeft will return a number (bytes) indicating how much space    *}
  636. {*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
  637. {*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
  638. {*  "action code" will return a result of 0.  Use this function when it is  *}
  639. {*  important to avoid program delays due to calls to output procedures or  *}
  640. {*  to prioritize the reception of data (to prevent overflows).             *}
  641. {*                                                                          *}
  642. {****************************************************************************}
  643.  
  644. Function ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  645.  
  646. Begin
  647.   ComBufferLeft := 0;
  648.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  649.   IO := Upcase(IO);
  650.  
  651.   If IO = 'I' Then
  652.     If C_InHead[ComPort] >= C_InTail[ComPort] Then
  653.       ComBufferLeft := C_InSize[ComPort]-(C_InHead[ComPort]-C_InTail[ComPort])
  654.     Else
  655.       ComBufferLeft := C_InTail[ComPort]-C_InHead[ComPort];
  656.  
  657.   If IO = 'O' Then
  658.     If C_OutHead[ComPort] >= C_OutTail[ComPort] Then
  659.       ComBufferLeft := C_OutHead[ComPort]-C_OutTail[ComPort]
  660.     Else
  661.       ComBufferLeft := C_OutSize[ComPort]-(C_OutTail[ComPort]-C_OutHead[ComPort]);
  662. End;
  663.  
  664. {****************************************************************************}
  665. {*                                                                          *}
  666. {*  Procedure ComWaitForClear(ComPort:Byte)                                 *}
  667. {*                                                                          *}
  668. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  669. {*                    Exits immediately if out of range or port unopened.   *}
  670. {*                                                                          *}
  671. {*  A call to ComWaitForClear will stop processing until the selected out-  *}
  672. {*  put buffer is completely emptied.  Typically used just before a call    *}
  673. {*  to the CloseCom procedure to prevent premature cut-off of messages in   *}
  674. {*  transit.                                                                *}
  675. {*                                                                          *}
  676. {****************************************************************************}
  677.  
  678. Procedure ComWaitForClear(ComPort:Byte);
  679.  
  680. Var
  681.   Empty : Boolean;
  682.  
  683. Begin
  684.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  685.   Repeat
  686.     Empty := (C_Status[ComPort] And $04) = $04;
  687.     Empty := Empty And ((Port[C_PortAddr[ComPort]+C_IER] And $02) = $00);
  688.   Until Empty;
  689. End;
  690.  
  691. {****************************************************************************}
  692. {*                                                                          *}
  693. {*  Procedure ComWrite(ComPort:Byte; St:String)                             *}
  694. {*                                                                          *}
  695. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  696. {*                    Exits immediately if out of range or port unopened.   *}
  697. {*  St:String     ->  String to send                                        *}
  698. {*                                                                          *}
  699. {*  Sends string <St> out communications port <ComPort>.                    *}
  700. {*                                                                          *}
  701. {****************************************************************************}
  702.  
  703. Procedure ComWrite(ComPort:Byte; St:String);
  704.  
  705. Var
  706.   X : Byte;
  707.  
  708. Begin
  709.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  710.  
  711.   For X := 1 To Length(St) Do
  712.     ComWriteChW(ComPort,St[X]);
  713. End;
  714.  
  715. {****************************************************************************}
  716. {*                                                                          *}
  717. {*  Procedure ComWriteln(ComPort:Byte; St:String);                          *}
  718. {*                                                                          *}
  719. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  720. {*                    Exits immediately if out of range or port unopened.   *}
  721. {*  St:String     ->  String to send                                        *}
  722. {*                                                                          *}
  723. {*  Sends string <St> with a CR and LF appended.                            *}
  724. {*                                                                          *}
  725. {****************************************************************************}
  726.  
  727. Procedure ComWriteln(ComPort:Byte; St:String);
  728.  
  729. Var
  730.   X : Byte;
  731.  
  732. Begin
  733.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  734.  
  735.   For X := 1 To Length(St) Do
  736.     ComWriteChW(ComPort,St[X]);
  737.   ComWriteChW(ComPort,#13);
  738.   ComWriteChW(ComPort,#10);
  739. End;
  740.  
  741. {****************************************************************************}
  742. {*                                                                          *}
  743. {*  Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);         *}
  744. {*                                                                          *}
  745. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  746. {*                    Exits immediately if out of range or port unopened.   *}
  747. {*  St:String     ->  String to send                                        *}
  748. {*  Dly:Word      ->  Time, in milliseconds, to delay between each char.    *}
  749. {*                                                                          *}
  750. {*  ComWriteWithDelay will send string <St> to port <ComPort>, delaying     *}
  751. {*  for <Dly> milliseconds between each character.  Useful for systems that *}
  752. {*  cannot keep up with transmissions sent at full speed.                   *}
  753. {*                                                                          *}
  754. {****************************************************************************}
  755.  
  756. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  757.  
  758. Var
  759.   X : Byte;
  760.  
  761. Begin
  762.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  763.  
  764.   ComWaitForClear(ComPort);
  765.   For X := 1 To Length(St) Do
  766.     Begin
  767.       ComWriteChW(ComPort,St[X]);
  768.       ComWaitForClear(ComPort);
  769.       Delay(Dly);
  770.     End;
  771. End;
  772.  
  773. {****************************************************************************}
  774. {*                                                                          *}
  775. {* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
  776. {*                                                                          *}
  777. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  778. {*                    Exits immediately if out of range or port unopened.   *}
  779. {*  St:String     <-  Edited string from remote                             *}
  780. {*  Size:Byte;    ->  Maximum allowable length of input                     *}
  781. {*  Echo:Boolean; ->  Set TRUE to echo received characters                  *}
  782. {*                                                                          *}
  783. {*  ComReadln is the remote equivalent of the standard Pascal READLN pro-   *}
  784. {*  cedure with some enhancements.  ComReadln will accept an entry of up to *}
  785. {*  40 printable ASCII characters, supporting ^H and ^X editing commands.   *}
  786. {*  Echo-back of the entry (for full-duplex operation) is optional.  All    *}
  787. {*  control characters, as well as non-ASCII (8th bit set) characters are   *}
  788. {*  stripped.  If <Echo> is enabled, ASCII BEL (^G) characters are sent     *}
  789. {*  when erroneous characters are intercepted.  Upon receipt of a ^M (CR),  *}
  790. {*  the procedure is terminated and the final string result returned.       *}
  791. {*                                                                          *}
  792. {****************************************************************************}
  793.  
  794. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  795.  
  796. Var
  797.   Len,X : Byte;
  798.   Ch : Char;
  799.   Done : Boolean;
  800.  
  801. Begin
  802.   St := '';
  803.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  804.  
  805.   Done := False;
  806.   Repeat
  807.     Len := Length(St);
  808.     Ch := Chr(Ord(ComReadChW(ComPort)) And $7F);
  809.  
  810.     Case Ch Of
  811.       ^H : If Len > 0 Then
  812.              Begin
  813.                Dec(Len);
  814.                St[0] := Chr(Len);
  815.                If Echo Then ComWrite(ComPort,#8#32#8);
  816.              End
  817.            Else
  818.              ComWriteChW(ComPort,^G);
  819.       ^M : Begin
  820.              Done := True;
  821.              If Echo Then ComWrite(ComPort,#13#10);
  822.            End;
  823.       ^X : Begin
  824.              St := '';
  825.              If Len = 0 Then ComWriteCh(ComPort,^G);
  826.              If Echo Then
  827.                For X := 1 to Len Do
  828.                  ComWrite(ComPort,#8#32#8);
  829.            End;
  830.       #32..#127 : If Len < Size Then
  831.                     Begin
  832.                       Inc(Len);
  833.                       St[Len] := Ch;
  834.                       St[0] := Chr(Len);
  835.                       If Echo Then ComWriteChW(ComPort,Ch);
  836.                     End
  837.                   Else
  838.                     If Echo Then ComWriteChW(ComPort,^G);
  839.     Else
  840.       If Echo Then ComWriteChW(ComPort,^G)
  841.     End;
  842.  
  843.   Until Done;
  844. End;
  845.  
  846. {****************************************************************************}
  847. {*                                                                          *}
  848. {*  Function ComExist(ComPort:Byte) : Boolean                               *}
  849. {*                                                                          *}
  850. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  851. {*                    Returns FALSE if out of range                         *}
  852. {*  Returns TRUE if hardware for selected port is detected & tests OK       *}
  853. {*                                                                          *}
  854. {*  Function ComExist performs a high-speed short loopback test on the      *}
  855. {*  selected port to determine if it indeed exists.  Use this function      *}
  856. {*  before attempts to OPEN a port for I/O (although this function is       *}
  857. {*  called by OpenCom to prevent such an occurance).                        *}
  858. {*  NOTE!  Although pains are taken to preserve the 8250 state before the   *}
  859. {*  port test takes place, it is nonetheless recommended that this function *}
  860. {*  NOT be called while a port is actually OPEN.  Doing so may cause the    *}
  861. {*  port to behave erratically.                                             *}
  862. {*                                                                          *}
  863. {****************************************************************************}
  864.  
  865. Function ComExist(ComPort:Byte) : Boolean;
  866.  
  867. Const
  868.   TestByte1 : Byte = $0F;
  869.   TestByte2 : Byte = $F1;
  870.  
  871. Var
  872.   P : Word;
  873.   M,L,B1,B2 : Byte;
  874.  
  875. Begin
  876.   ComExist := False;
  877.   If (ComPort<1) Or (ComPort>C_MaxPort) Then Exit;
  878.  
  879.   P := C_PortAddr[ComPort];
  880.   M := Port[P+C_MCR];                            { Save MCR }
  881.   L := Port[P+C_LCR];                            { Save LCR }
  882.   Port[P+C_MCR] := $10;                          { Enable loopback mode }
  883.   Port[P+C_LCR] := $80;                          { Enable divisor latch mode }
  884.   B1 := Port[P];                                 { Save current baud rate }
  885.   B2 := Port[P+1];
  886.   Port[P] := 4;                                  { Set baud rate to 28000 }
  887.   Port[P+1] := 0;
  888.   Port[P+C_LCR] := $03;                          { Transmit mode 28000:8N1 }
  889.  
  890.   Port[P] := TestByte1;                          { Test byte #1 }
  891.   Delay(20);                                     { Wait a bit for loopback }
  892.   If Port[P] <> TestByte1 Then Exit;             { Exit w/error if not echoed }
  893.   Port[P] := TestByte2;                          { Test byte #2 }
  894.   Delay(20);                                     { Wait a bit for loopback }
  895.   If Port[P] <> TestByte2 Then Exit;             { Exit w/error if not echoed }
  896.  
  897.   ComExist := True;                              { Test passed: Port exists }
  898.   Port[P+C_LCR] := $80;                          { Restore baud rate }
  899.   Port[P] := B1;
  900.   Port[P+1] := B2;
  901.   Port[P+C_LCR] := L;                            { Restore parameters }
  902.   Port[P+C_MCR] := M;                            { Restore control lines }
  903. End;
  904.  
  905. {****************************************************************************}
  906. {*                                                                          *}
  907. {*  Function ComTrueBaud(Baud:Longint) : Real                               *}
  908. {*                                                                          *}
  909. {*  Baud:Longint  ->  User baud rate to test.                               *}
  910. {*                    Should be between C_MinBaud and C_MaxBaud.            *}
  911. {*  Returns the actual baud rate based on the accuracy of the 8250 divider. *}
  912. {*                                                                          *}
  913. {*  The ASYNC11 communications package allows the programmer to select ANY  *}
  914. {*  baud rate, not just those that are predefined by the BIOS or other      *}
  915. {*  agency.  Since the 8250 uses a divider/counter chain to generate it's   *}
  916. {*  baud clock, many non-standard baud rates can be generated.  However,    *}
  917. {*  the binary counter/divider is not always capable of generating the      *}
  918. {*  EXACT baud rate desired by a user.  This function, when passed a valid  *}
  919. {*  baud rate, will return the ACTUAL baud rate that will be generated.     *}
  920. {*  The baud rate is based on a 8250 input clock rate of 1.73728 MHz.       *}
  921. {*                                                                          *}
  922. {****************************************************************************}
  923.  
  924. Function ComTrueBaud(Baud:Longint) : Real;
  925.  
  926. Var
  927.   X : Real;
  928.   Y : Word;
  929.  
  930. Begin
  931.   X := Baud;
  932.   If X < C_MinBaud Then X := C_MinBaud;
  933.   If X > C_MaxBaud Then X := C_MaxBaud;
  934.   ComTrueBaud := 115200 / Round($900/(X/50));
  935. End;
  936.  
  937. {****************************************************************************}
  938. {*                                                                          *}
  939. {*  Procedure ComParams(ComPort:Byte; Baud:Longint;                         *}
  940. {*                      WordSize:Byte; Parity:Char; StopBits:Byte);         *}
  941. {*                                                                          *}
  942. {*  ComPort:Byte   ->  Port # to initialize.  Must be (1 - C_MaxCom)        *}
  943. {*                     Procedure aborted if port # invalid or unopened.     *}
  944. {*  Baud:Longint   ->  Desired baud rate.  Should be (C_MinBaud - C_MaxBaud)*}
  945. {*                     C_MinBaud or C_MaxBaud used if out of range.         *}
  946. {*  WordSize:Byte  ->  Word size, in bits.  Must be 5 - 8 bits.             *}
  947. {*                     8-bit word used if out of range.                     *}
  948. {*  Parity:Char    ->  Parity classification.                               *}
  949. {*                     May be N)one, E)ven, O)dd, M)ark or S)pace.          *}
  950. {*                     N)one selected if classification unknown.            *}
  951. {*  StopBits:Byte  ->  # of stop bits to pad character with.  Range (1-2)   *}
  952. {*                     1 stop bit used if out of range.                     *}
  953. {*                                                                          *}
  954. {*  ComParams is used to configure an OPEN'ed port for the desired comm-    *}
  955. {*  unications parameters, namely baud rate, word size, parity form and     *}
  956. {*  # of stop bits.  A call to this procedure will set up the port approp-  *}
  957. {*  riately, as well as assert the DTR, RTS and OUT2 control lines and      *}
  958. {*  clear all buffers.                                                      *}
  959. {*                                                                          *}
  960. {****************************************************************************}
  961.  
  962. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  963.  
  964. Const
  965.   C_Stopbit1    = $00;                 { Bit masks for parity, stopbits }
  966.   C_Stopbit2    = $04;
  967.   C_NoParity    = $00;
  968.   C_OddParity   = $08;
  969.   C_EvenParity  = $18;
  970.   C_MarkParity  = $28;
  971.   C_SpaceParity = $38;
  972.  
  973. Var
  974.   X : Real;
  975.   Y,P : Word;
  976.   DivMSB,DivLSB,BaudB : Byte;
  977.   WS,SB,PTY : Byte;
  978.  
  979. Begin
  980.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  981.  
  982.   Inline($FA);
  983.   P := C_PortAddr[ComPort];
  984.  
  985.   { Calculate baud rate divisors }
  986.  
  987.   X := Baud;
  988.   If X < C_MinBaud Then X := C_MinBaud;
  989.   If X > C_MaxBaud Then X := C_MaxBaud;
  990.  
  991.   Y := Round($900/(X/50));
  992.   DivMSB := Hi(Y);
  993.   DivLSB := Lo(Y);
  994.  
  995.   { Determine parity mask }
  996.   { Default if unknown: No parity }
  997.  
  998.   Case UpCase(Parity) Of
  999.     'N' : PTY := C_NoParity;
  1000.     'E' : PTY := C_EvenParity;
  1001.     'O' : PTY := C_OddParity;
  1002.     'M' : PTY := C_MarkParity;
  1003.     'S' : PTY := C_SpaceParity;
  1004.   Else
  1005.     PTY := C_NoParity;
  1006.   End;
  1007.  
  1008.   { Determine stop-bit mask }
  1009.   { Default if out of range: 1 Stop bit }
  1010.  
  1011.   Case StopBits Of
  1012.     1 : SB := C_StopBit1;
  1013.     2 : SB := C_StopBit2;
  1014.   Else
  1015.     SB := C_StopBit1;
  1016.   End;
  1017.  
  1018.   { Determine word-size mask }
  1019.   { Default if out of range: 8 bit word size }
  1020.  
  1021.   If (WordSize >= 5) And (WordSize <= 8) Then
  1022.     WS := WordSize - 5
  1023.   Else
  1024.     WS := 3;
  1025.  
  1026.   { Initialize line-control register }
  1027.  
  1028.   Y := Port[P] + Port[P+C_LSR];
  1029.  
  1030.   Port[P+C_LCR] := WS + SB + PTY;
  1031.  
  1032.   { Initialize baud rate divisor latches }
  1033.  
  1034.   Port[P+C_LCR] := Port[P+C_LCR] Or $80;
  1035.   Port[P] := DivLSB;
  1036.   Port[P+1] := DivMSB;
  1037.   Port[P+C_LCR] := Port[P+C_LCR] And $7F;
  1038.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1039.  
  1040.   { Assert RS323 control lines (DTR,RTS,OUT2) & exit }
  1041.  
  1042.   Port[P+C_MCR] := $0B;
  1043.   ClearCom(ComPort,'B');
  1044.  
  1045.   {begin new stuff srl*}
  1046.   Port[$20] := $20;
  1047.   If C_CascadeOK then
  1048.     Port[$A0] := $20;
  1049.   {end new stuff srl*}
  1050.  
  1051.   Inline($FB);
  1052.  
  1053. End;
  1054.  
  1055. {****************************************************************************}
  1056. {*                                                                          *}
  1057. {*  Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
  1058. {*                                                                          *}
  1059. {*  ComPort:Byte        ->  Port # to OPEN (1 - C_MaxCom)                   *}
  1060. {*                          Request will fail if out of range or port OPEN  *}
  1061. {*  InBufferSize:Word   ->  Requested size of input (receive) buffer        *}
  1062. {*  OutBufferSize:Word  ->  Requested size of output (transmit) buffer      *}
  1063. {*  Returns success/fail status of OPEN request (TRUE if OPEN successful)   *}
  1064. {*                                                                          *}
  1065. {*  OpenCom must be called before any activity (other than existence check, *}
  1066. {*  see the ComExist function) takes place.  OpenCom initializes the        *}
  1067. {*  interrupt drivers and serial communications hardware for the selected   *}
  1068. {*  port, preparing it for I/O.  Memory for buffers is allocated on the     *}
  1069. {*  Pascal "heap", thus freeing data-segment memory for larger more data-   *}
  1070. {*  intensive programs.  Once a port has been OPENed, a call to ComParams   *}
  1071. {*  should be made to set up communications parameters (baud rate, parity   *}
  1072. {*  and the like).  Once this is done, I/O can take place on the port.      *}
  1073. {*  OpenCom will return a TRUE value if the opening procedure was success-  *}
  1074. {*  ful, or FALSE if it is not.                                             *}
  1075. {*                                                                          *}
  1076. {****************************************************************************}
  1077.  
  1078. Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  1079.  
  1080. Var
  1081.   TempVec : Pointer;
  1082.   P : Word;
  1083.   IntLn,Cas_IntLn,X : Byte;
  1084.  
  1085. Begin
  1086.   { Ensure that port was not previously open }
  1087.  
  1088.   OpenCom := False;
  1089.   C_CascadeOK := False;
  1090.   C_cascade :=0;
  1091.   If (ComPort<1) Or (ComPort>C_MaxPort) Or C_PortOpen[ComPort] Then Exit;
  1092.   C_msrport:=c_portaddr[comport]+c_msr;
  1093.  
  1094.   { Clear any pending activity from 8250 interrupt queue }
  1095.  
  1096.   Inline($FA);
  1097.  
  1098.   { Set up interrupt vectors & 8259 PIC }
  1099.   P := C_PortAddr[ComPort];
  1100.   oldier:=port[P+c_ier];
  1101.   oldmcr:=port[P+c_mcr];
  1102.   Port[P+C_IER] := $0D;
  1103.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1104.  
  1105.   IntLn := C_PortInt[ComPort];
  1106.   If IntLn > 7 then
  1107.      C_CascadeOK := true;
  1108.  
  1109.   If C_CascadeOK then
  1110.     Begin
  1111.       Cas_IntLn := IntLn-8;
  1112.       GetIntVec($70+Cas_IntLn,TempVec);
  1113.       If C_OldINTVec[IntLn] <> TempVec Then
  1114.         Begin
  1115.           C_Cascade := 1;
  1116.           C_OldINTVec[IntLn] := TempVec;
  1117.           SetIntVec($70+Cas_IntLn,@Int_Handler);
  1118.           Port[$21] := Port[$21] And (($01 SHL $02) XOR $FF);
  1119.           X := Port[$21];
  1120.           Port[$A1] := Port[$A1] And (($01 SHL Cas_IntLn) XOR $FF);
  1121.           X := Port[$A1];
  1122.         End;
  1123.     End
  1124.   else
  1125.     Begin
  1126.       GetIntVec(8+IntLn,TempVec);
  1127.       If C_OldINTVec[IntLn] <> TempVec Then
  1128.         Begin
  1129.           C_OldINTVec[IntLn] := TempVec;
  1130.           SetIntVec(8+IntLn,@Int_Handler);
  1131.           Port[$21] := Port[$21] And (($01 SHL IntLn) XOR $FF);
  1132.           X := Port[$21];
  1133.         End;
  1134.     End;
  1135.  
  1136.   { new stuff srl*}
  1137.   Port[P+C_MCR] := $0B;
  1138.  
  1139.   { Allocate memory for I/O buffers }
  1140.  
  1141.   C_InSize[ComPort] := InBufferSize;
  1142.   C_OutSize[ComPort] := OutBufferSize;
  1143.   GetMem(C_InBufPtr[ComPort],InBufferSize);
  1144.   GetMem(C_OutBufPtr[ComPort],OutBufferSize);
  1145.  
  1146.   { Set up default parameters for port }
  1147.  
  1148.   C_RTSOn[ComPort] := InBufferSize - 2;
  1149.   C_RTSOff[ComPort] := InBufferSize - 1;
  1150.   C_StartChar[ComPort] := ^Q;
  1151.   C_StopChar[ComPort] := ^S;
  1152.   C_PortOpen[ComPort] := True;
  1153.   OpenCom := True;
  1154.  
  1155.   Inline($FB);
  1156. End;
  1157.  
  1158. {****************************************************************************}
  1159. {*                                                                          *}
  1160. {*  Procedure CloseCom(ComPort:Byte)                                        *}
  1161. {*                                                                          *}
  1162. {*  ComPort:Byte  ->  Port # to close                                       *}
  1163. {*                    Request ignored if port closed or out of range.       *}
  1164. {*                                                                          *}
  1165. {*  CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
  1166. {*  buffers and drop the DTR and RTS signal lines for a port opened with    *}
  1167. {*  the OpenCom function.  It should be called before exiting your program  *}
  1168. {*  to ensure that the port is properly shut down.                          *}
  1169. {*  NOTE:  CloseCom shuts down a communications channel IMMEDIATELY,        *}
  1170. {*         even if there is data present in the input or output buffers.    *}
  1171. {*         Therefore, you may wish to call the ComWaitForClear procedure    *}
  1172. {*         before closing the ports.                                        *}
  1173. {*                                                                          *}
  1174. {****************************************************************************}
  1175.  
  1176. Procedure CloseCom(ComPort:Byte);
  1177.  
  1178. Var
  1179.   ClosePort : Boolean;
  1180.   P,IntLn,Cas_IntLn,X : Word;
  1181.  
  1182. Begin
  1183.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  1184.  
  1185.   { Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
  1186.  
  1187.   Inline($FA);
  1188.   P := C_PortAddr[ComPort];
  1189.   Port[P+C_IER] := oldier;
  1190.   C_PortOpen[ComPort] := False;
  1191.  
  1192.   { Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
  1193.  
  1194.   IntLn := C_PortInt[ComPort];
  1195.   ClosePort := True;
  1196.   For X := 1 To C_MaxCom Do
  1197.     If C_PortOpen[X] And (C_PortInt[X] = IntLn) Then
  1198.       ClosePort := False;
  1199.  
  1200.   If ClosePort Then
  1201.     If C_CascadeOk then
  1202.       Begin
  1203.         Cas_IntLn := IntLn-8;
  1204.         Port[$21] := Port[$21] Or ($01 SHR $02);
  1205.         X := Port[$21];
  1206.         Port[$A1] := Port[$A1] Or ($01 SHR Cas_IntLn);
  1207.         X := Port[$A1];
  1208.         SetIntVec($70+Cas_IntLn,C_OldINTVec[IntLn]);
  1209.       End
  1210.     else
  1211.       Begin
  1212.         Port[$21] := Port[$21] Or ($01 SHR IntLn);
  1213.         X := Port[$21];
  1214.         SetIntVec(8+IntLn,C_OldINTVec[IntLn]);
  1215.       End;
  1216.  
  1217.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1218.  
  1219.   { Deallocate buffers }
  1220.  
  1221.   FreeMem(C_InBufPtr[ComPort],C_InSize[ComPort]);
  1222.   FreeMem(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
  1223.   Inline($FB);
  1224. End;
  1225.  
  1226. {****************************************************************************}
  1227. {*                                                                          *}
  1228. {*  Procedure CloseAllComs                                                  *}
  1229. {*                                                                          *}
  1230. {*  CloseAllComs will CLOSE all currently OPENed ports.  See the CloseCom   *}
  1231. {*  procedure description for more details.                                 *}
  1232. {*                                                                          *}
  1233. {****************************************************************************}
  1234.  
  1235. Procedure CloseAllComs;
  1236.  
  1237. Var
  1238.   X : Byte;
  1239.  
  1240. Begin
  1241.   For X := 1 To C_MaxCom Do
  1242.     If C_PortOpen[X] Then
  1243.       CloseCom(X);
  1244. End;
  1245.  
  1246. {****************************************************************************}
  1247. {*                                                                          *}
  1248. {*                        UNIT Initialization Code                          *}
  1249. {*                                                                          *}
  1250. {****************************************************************************}
  1251.  
  1252. Begin
  1253.   For x := 1 to C_MaxPort Do
  1254.     Begin
  1255.       C_PortOpen[x] := False;
  1256.       C_InBufPtr[x] := Nil;
  1257.       C_OutBufPtr[x] := Nil;
  1258.       C_OldIntVec[x] := Nil;
  1259.       C_InHead[x] := 0;
  1260.       C_OutHead[x] := 0;
  1261.       C_InTail[x] := 0;
  1262.       C_OutTail[x] := 0;
  1263.       C_InSize[x] := 0;
  1264.       C_OutSize[x] := 0;
  1265.       C_RTSOn[x] := $FFFF;
  1266.       C_RTSOff[x] := $FFFF;
  1267.       C_StartChar[x] := ^Q;
  1268.       C_StopChar[x] := ^S;
  1269.       C_Status[x] := $05;
  1270.       C_Ctrl[x] := 0;
  1271.       C_XL3Ptr[x] := 0;
  1272.       C_buffull[x]:=0;
  1273.       C_cascade := 0;
  1274.     End;
  1275. End.
  1276.